// inlude 路径在文件中包含就不用在 编译的时候包含了
#include <stdio.h>
#include <mysql/mysql.h>
#include <string.h>

int main(int argc, char* argv[])
{
    //初始化连接
    MYSQL conn;
    MYSQL *pconn = mysql_init(&conn);
    //建立连接
    pconn = mysql_real_connect(pconn, "localhost", "root", "123456", "sqlinject", 0, NULL, 0);
    if(pconn == NULL)
    {
        //注意：如果建立连接失败，使用mysql_error(pconn) 此时pconn为空 会有大问题
        printf("%s\n", mysql_error(&conn));
        mysql_close(pconn);
        return 1;
    }
    // 初始化stmt
    MYSQL_STMT * stmt = mysql_stmt_init(pconn);
    //如果返回为空 stmt 与 连接建立映射失败
    if(stmt == NULL)
    {
        //打印错误码 错误信息
        printf("%d,%s\n", mysql_errno(pconn), mysql_error(pconn));
        //关闭连接
        mysql_stmt_close(stmt);
        mysql_close(pconn);
        return 1;
    }
    const char* sql = "select * from user where id > ?";
    //预处理初始化
    int ret = mysql_stmt_prepare(stmt, sql, strlen(sql));
    // 非0失败
    if(ret)
    {
        //打印错误码 错误信息
        printf("%d,%s\n", mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
        //关闭连接
        mysql_stmt_close(stmt);
        mysql_close(pconn);
        return 1;
    }
    //获取 模板化参数的占位符
    int count = mysql_stmt_param_count(stmt);
    if(count != 1)
    {
        //打印错误码 错误信息
        printf("%d,%s\n", mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
        //关闭连接
        mysql_stmt_close(stmt);
        mysql_close(pconn);
        return 1;
    }
    //设置输入参数
    MYSQL_BIND bind;
    int id = 0;
    // 第一个参数传地址
    memset(&bind, 0, sizeof(bind));
    
    //绑定参数
    bind.buffer = &id;
    bind.buffer_length = sizeof(int);
    bind.buffer_type = MYSQL_TYPE_LONG;

    // STMT 与 bind 绑定
    ret = mysql_stmt_bind_param(stmt, &bind);
    if(ret)
    {
        //打印错误码 错误信息
        printf("%d,%s\n", mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
        //关闭连接
        mysql_stmt_close(stmt);
        mysql_close(pconn);
        return 1;
    }
    
    //设置参数值
    id = 1;

    // 执行sql语句
    ret = mysql_stmt_execute(stmt);
    if(ret)
    {
        //打印错误码 错误信息
        printf("%d,%s\n", mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
        //关闭连接
        mysql_stmt_close(stmt);
        mysql_close(pconn);
        return 1;
    }

    // 执行的sql语句有返回值，获取元数据信息
    MYSQL_RES *res = mysql_stmt_result_metadata(stmt);
    if(res == NULL)
    {
        //打印错误码 错误信息
        printf("%d,%s\n", mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
        //关闭连接
        mysql_stmt_close(stmt);
        mysql_close(pconn);
        return 1;
    }
    // 先获取field字段
    // 获取列的个数  注意mysql_num_fields 参数为结果集
    int cols = mysql_num_fields(res);
    printf("%d\n", cols);
    // 获取第一行数据就是field字段
    MYSQL_FIELD *field = mysql_fetch_field(res);
    // 在循环中不断地打印每一列的字段
    for(int i = 0; i < cols; i++)
    {
        printf("%s\t", field[i].name);
    }
    printf("\n");
    
    // 获取每行数据信息
    
    // 设置输出参数（后续获取的每一行数据都存储在这三个字段中）
    int res_id;
    // 作为输出参数就不用设置长度
    char res_name[256];
    char res_passwrd[256];

    MYSQL_BIND res_bind[3];
    memset(res_bind, 0, sizeof(res_bind));  // 全部字段初始化为0
    res_bind[0].buffer = &res_id;
    res_bind[0].buffer_length = sizeof(int);
    res_bind[0].buffer_type = MYSQL_TYPE_LONG;

    res_bind[1].buffer = res_name;
    res_bind[1].buffer_length = sizeof(res_name);
    res_bind[1].buffer_type = MYSQL_TYPE_VAR_STRING;

    res_bind[2].buffer = res_passwrd;
    res_bind[2].buffer_length = sizeof(res_passwrd);
    res_bind[2].buffer_type = MYSQL_TYPE_VAR_STRING;

    // 绑定操作 将stmt 与 res_bind 绑定
    ret = mysql_stmt_bind_result(stmt, res_bind);
    if(ret)
    {
        //打印错误码 错误信息
        printf("%d,%s\n", mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
        //关闭连接
        mysql_stmt_close(stmt);
        mysql_close(pconn);
        return 1;
    }
    // 得到数据信息，将结果集进行缓冲处理 后面会使用mysql_stmt_fetch 拿到每行数据
    ret = mysql_stmt_store_result(stmt);
    if(ret)
    {
        //打印错误码 错误信息
        printf("%d,%s\n", mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
        //关闭连接
        mysql_stmt_close(stmt);
        mysql_close(pconn);
        return 1;
    }
    // 真正的获取数据
    while(1)
    {
        int status = mysql_stmt_fetch(stmt);
        if(status == 1 || status == MYSQL_NO_DATA)
        {
            break;
        }
        printf("%d\t%s\t%s\n", res_id, res_name, res_passwrd);
    }

    //关闭预处理 释放结果集 关闭连接
    mysql_free_result(res);
    mysql_stmt_close(stmt);
    mysql_close(pconn);
    return 0;
}